#include "rewine.h"

#include "rewine/LoaderSingleton.hpp"
#include "rewine/LoggerSingleton.hpp"
#include "rewine/impl/CCustomExport.hpp"

#include <cstdio>
#include <cstring>

using namespace rewine;
using namespace std;

using strlenA = int (*)(LPCSTR);
using lstrlenA = int (CDECL *)(LPCSTR);
using wstrlenA = int (WINAPI *)(LPCSTR);

int WINAPI my_wstrlenA(LPCSTR s) {
    return 100 + strlen(s);
}

int main(int argc, char* argv[]) {
    for (int i = 0; i < argc; ++i) {
        fprintf(stdout, "%d %s\n", i, argv[i]);
    }
    fflush(stdout);

    auto& pathResolver = g_Loader->getPathResolver();
    auto& libManager = g_Loader->getLibManager();
    auto& symbolResolver = g_Loader->getSymbolResolver();

    g_Logger->onDebug();

    //pathResolver.add("/usr/local/lib64/wine");
    pathResolver.add(".");
    pathResolver.add("/as/code/rewine/tmp/x64");

    g_Loader->openImage("/as/code/play/dllcpt2/test1/B.dll", true);

    auto mystrlen = (wstrlenA) &my_wstrlenA;
    g_Logger->info(__FLF__, "&mystrlen = {}", (PVOID) mystrlen);
    {
        int mylen = mystrlen("Hello");
        g_Logger->info(__FLF__, "mystrlen() = {}", mylen);
    }

    auto pLibKernelbase = libManager.get("kernelbase.dll");
    auto spExportMystrlen = CCustomExport::create();
    spExportMystrlen->setValue((PVOID) mystrlen);
    pLibKernelbase->setOverride("lstrlenA", spExportMystrlen, true);

    g_Loader->openImage("kernel32.dll", true);

    auto spExportFstrlen = CCustomExport::create();
    bool succeed = symbolResolver.resolveAndBind(nullptr, "KERNEL32.dll", "lstrlenA", -1, spExportFstrlen->getValueSynchronizerRef(), true);
    if (!succeed) {
        g_Logger->error(__FLF__, "resolve ret=false");
        return 1;
    }

    auto pfn_strlenA = (wstrlenA) spExportFstrlen->getValue();
    g_Logger->info(__FLF__, "&strlenA = {}", (PVOID) pfn_strlenA);
    {
        int len = pfn_strlenA("Hello");
        g_Logger->info(__FLF__, "strlenA() = {}", len);
    }

    return 0;
}
